use rstar::{RTreeObject, AABB};
use rustc_hash::FxHashMap;
#[cfg(feature = "wasm")]
use wasm_bindgen::prelude::wasm_bindgen;

#[cfg(feature = "napi")]
use napi_derive::napi;

use crate::F64Point;

#[derive(Clone)]
pub struct EntityAABBObject {
    pub entity_id: String,
    pub min_pos: F64Point,
    pub max_pos: F64Point,
    pub camp: Option<f64>
}

impl PartialEq for EntityAABBObject {
    fn eq(&self, other: &Self) -> bool {
        self.entity_id == other.entity_id
    }
}

impl RTreeObject for EntityAABBObject {
    type Envelope = AABB<F64Point>;

    fn envelope(&self) -> Self::Envelope {
        AABB::from_corners(self.min_pos, self.max_pos)
    }
}

impl Eq for EntityAABBObject {}

#[cfg_attr(feature = "wasm", wasm_bindgen)]
#[cfg_attr(feature = "napi", napi)]
pub struct RTree {
    rtree: rstar::RTree<EntityAABBObject>,
    entity_map: FxHashMap<String, EntityAABBObject>
}

#[cfg(feature = "wasm")]
#[wasm_bindgen]
impl RTree {
    ///
    /// 创建一个新的RTree
    /// 
    #[wasm_bindgen(constructor)]
    pub fn new() -> Self {
        Self::_new()
    }

    ///
    /// 插入或更新一个实体
    /// 
    pub fn insert(&mut self, entity_id: String, min_pos_x: f64, min_pos_y: f64, max_pos_x: f64, max_pos_y: f64, camp: Option<f64>) {
        self._insert(&entity_id, min_pos_x, min_pos_y, max_pos_x, max_pos_y, camp);
    }

    ///
    /// 移除一个实体
    /// 
    pub fn remove(&mut self, entity_id: String) {
        self._remove(&entity_id);
    }

    ///
    /// 重建RTree
    /// 
    pub fn rebuild(&mut self) {
        self._rebuild();
    }

    ///
    /// 清空RTree
    /// 
    pub fn clear_rtree(&mut self) {
        self._clear_rtree();
    }

    ///
    /// 清空实体映射
    /// 
    pub fn clear_entity_map(&mut self) {
        self._clear_entity_map();
    }

    ///
    /// 查询指定范围内的实体
    /// 
    pub fn query(&self, min_pos_x: f64, min_pos_y: f64, max_pos_x: f64, max_pos_y: f64, check_cross:bool) -> Vec<String> {
        self._query(min_pos_x, min_pos_y, max_pos_x, max_pos_y, check_cross)
    }

    ///
    /// 根据阵营查询指定范围内的实体
    /// 
    pub fn query_camp(&self, min_pos_x: f64, min_pos_y: f64, max_pos_x: f64, max_pos_y: f64, camp: f64, check_cross:bool) -> Vec<String> {
        self._query_camp(min_pos_x, min_pos_y, max_pos_x, max_pos_y, camp, check_cross)
    }

    ///
    /// 根据阵营查询指定范围内的敌对实体
    /// 
    pub fn query_enemy(&self, min_pos_x: f64, min_pos_y: f64, max_pos_x: f64, max_pos_y: f64, camp: f64, check_cross:bool) -> Vec<String> {
        self._query_enemy(min_pos_x, min_pos_y, max_pos_x, max_pos_y, camp, check_cross)
    }
}

#[cfg(feature = "napi")]
#[napi]
impl RTree {
    ///
    /// 创建一个新的RTree
    /// 
    #[napi(constructor)]
    pub fn new() -> Self {
        Self::_new()
    }

    ///
    /// 插入或更新一个实体
    /// 
    #[napi]
    pub fn insert(&mut self, entity_id: String, min_pos_x: f64, min_pos_y: f64, max_pos_x: f64, max_pos_y: f64, camp: Option<f64>) {
        self._insert(&entity_id, min_pos_x, min_pos_y, max_pos_x, max_pos_y, camp);
    }

    ///
    /// 移除一个实体
    /// 
    #[napi]
    pub fn remove(&mut self, entity_id: String) {
        self._remove(&entity_id);
    }

    ///
    /// 重建RTree
    /// 
    #[napi]
    pub fn rebuild(&mut self) {
        self._rebuild();
    }

    ///
    /// 清空RTree
    /// 
    #[napi]
    pub fn clear_rtree(&mut self) {
        self._clear_rtree();
    }

    ///
    /// 清空实体映射
    /// 
    #[napi]
    pub fn clear_entity_map(&mut self) {
        self._clear_entity_map();
    }

    ///
    /// 查询指定范围内的实体
    /// 
    #[napi]
    pub fn query(&self, min_pos_x: f64, min_pos_y: f64, max_pos_x: f64, max_pos_y: f64, check_cross:bool) -> Vec<String> {
        self._query(min_pos_x, min_pos_y, max_pos_x, max_pos_y, check_cross)
    }

    ///
    /// 根据阵营查询指定范围内的实体
    /// 
    #[napi]
    pub fn query_camp(&self, min_pos_x: f64, min_pos_y: f64, max_pos_x: f64, max_pos_y: f64, camp: f64, check_cross:bool) -> Vec<String> {
        self._query_camp(min_pos_x, min_pos_y, max_pos_x, max_pos_y, camp, check_cross)
    }

    ///
    /// 根据阵营查询指定范围内的敌对实体
    /// 
    #[napi]
    pub fn query_enemy(&self, min_pos_x: f64, min_pos_y: f64, max_pos_x: f64, max_pos_y: f64, camp: f64, check_cross:bool) -> Vec<String> {
        self._query_enemy(min_pos_x, min_pos_y, max_pos_x, max_pos_y, camp, check_cross)
    }
}

impl RTree {
    
    pub fn _new() -> Self {
        Self {
            rtree: rstar::RTree::new(),
            entity_map: FxHashMap::default()
        }
    }

    pub fn _insert(&mut self, entity_id: &str, min_pos_x: f64, min_pos_y: f64, max_pos_x: f64, max_pos_y: f64, camp:Option<f64>) {
        //只插入到entity_map中，不插入到rtree中，等待rebuild时插入
        self.entity_map.insert(entity_id.to_string(), EntityAABBObject {
            entity_id: entity_id.to_string(),
            min_pos: F64Point::new(min_pos_x, min_pos_y),
            max_pos: F64Point::new(max_pos_x, max_pos_y),
            camp
        });
    }

    pub fn _remove(&mut self, entity_id: &str) {
        self.entity_map.remove(entity_id);
    }

    pub fn _rebuild(&mut self) {
        self.rtree = rstar::RTree::bulk_load(self.entity_map.values().cloned().collect());
    }

    
    pub fn _clear_rtree(&mut self) {
        self.rtree = rstar::RTree::new();
    }

    pub fn _clear_entity_map(&mut self) {
        self.entity_map.clear();
        self.rtree = rstar::RTree::new();
    }

    pub fn _query(&self, min_pos_x: f64, min_pos_y: f64, max_pos_x: f64, max_pos_y: f64, check_cross:bool) -> Vec<String> {
        let aabb = AABB::from_corners(F64Point::new(min_pos_x, min_pos_y), F64Point::new(max_pos_x, max_pos_y));
        let mut result = Vec::new();
        if check_cross {
            self.rtree.locate_in_envelope_intersecting(&aabb).for_each(|item| {
                result.push(item.entity_id.clone());
            });
        } else {
            self.rtree.locate_in_envelope(&aabb).for_each(|item| {
                result.push(item.entity_id.clone());
            });
        }
        result
    }

    pub fn _query_camp(&self, min_pos_x: f64, min_pos_y: f64, max_pos_x: f64, max_pos_y: f64, camp: f64, check_cross:bool) -> Vec<String> {
        let aabb = AABB::from_corners(F64Point::new(min_pos_x, min_pos_y), F64Point::new(max_pos_x, max_pos_y));
        let mut result = Vec::new();
        if check_cross {
            self.rtree.locate_in_envelope_intersecting(&aabb).for_each(|item| {
                if item.camp == Some(camp) {
                    result.push(item.entity_id.clone());
                }
            });
        } else {
            self.rtree.locate_in_envelope(&aabb).for_each(|item| {
                if item.camp == Some(camp) {
                    result.push(item.entity_id.clone());
                }
            });
        }
        
        result
    }

    pub fn _query_enemy(&self, min_pos_x: f64, min_pos_y: f64, max_pos_x: f64, max_pos_y: f64, camp: f64, check_cross:bool) -> Vec<String> {
        let aabb = AABB::from_corners(F64Point::new(min_pos_x, min_pos_y), F64Point::new(max_pos_x, max_pos_y));
        let mut result = Vec::new();

        if check_cross {
            self.rtree.locate_in_envelope_intersecting(&aabb).for_each(|item| {
                if item.camp != Some(camp) {
                    result.push(item.entity_id.clone());
                }
            });
        } else {
            self.rtree.locate_in_envelope(&aabb).for_each(|item| {
                if item.camp != Some(camp) {
                    result.push(item.entity_id.clone());
                }
            });
        }

        // self.rtree.locate_in_envelope_intersecting(&aabb).for_each(|item| {
        //     if item.camp != Some(camp) {
        //         result.push(item.entity_id.clone());
        //     }
        // });
        result
    }

}

